package com.gitee.wsl.flowing.pipeline.context

import kotlin.coroutines.Continuation
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext

/**
 * Represents one frame in the coroutine call stack for debugger.
 * This interface is implemented by compiler-generated implementations of
 * [Continuation] interface.
 */
@SinceKotlin("1.3")
 interface CoroutineStackFrame {
    /**
     * Returns a reference to the stack frame of the caller of this frame,
     * that is a frame before this frame in coroutine call stack.
     * The result is `null` for the first frame of coroutine.
     */
     val callerFrame: CoroutineStackFrame?

    /**
     * Returns stack trace element that correspond to this stack frame.
     * The result is `null` if the stack trace element is not available for this frame.
     * In this case, the debugger represents this stack frame using the
     * result of [toString] function.
     */
     fun getStackTraceElement(): StackTraceElement?
}

/**
 * This is a fake coroutine stack frame. It is reported by [SuspendFunctionGun] when the debug agent
 * is trying to probe jobs state by peeking frames when the coroutine is running at the same time
 * and the frames sequence is concurrently changed.
 */
internal object StackWalkingFailedFrame : CoroutineStackFrame, Continuation<Unit> {
    override val callerFrame: CoroutineStackFrame? get() = null

    override fun getStackTraceElement(): StackTraceElement? {
        return StackTraceElement(
            StackWalkingFailed::class.simpleName,
            StackWalkingFailed::failedToCaptureStackFrame.name,
            "StackWalkingFailed.kt",
            8
        )
    }

    override val context: CoroutineContext
        get() = EmptyCoroutineContext

    override fun resumeWith(result: Result<Unit>) {
        StackWalkingFailed.failedToCaptureStackFrame()
    }
}

class StackTraceElement(simpleName: String?, name1: String, s2: String, i: Int)

internal object StackWalkingFailed {
    fun failedToCaptureStackFrame() {
        error(
            "Failed to capture stack frame. This is usually happens when a coroutine is running so" +
                    " the frame stack is changing quickly " +
                    "and the coroutine debug agent is unable to capture it concurrently." +
                    " You may retry running your test to see this particular trace."
        )
    }
}